package main

import (
	"context"
	"log"
	"os/signal"
	"syscall"
	"time"

	"github.com/pion/rtcp"
	"github.com/pion/sdp/v3"
	"github.com/yapingcat/gomedia/mpeg2"

	"gogs.smarteye.com/smarteye/gortc/bvrtc"
	"gogs.smarteye.com/smarteye/gortc/bvrtc/examples/api"
	"gogs.smarteye.com/smarteye/gortc/pkg/description"
	"gogs.smarteye.com/smarteye/gortc/pkg/format"
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

type pcHandle struct {
}

func (c *pcHandle) OnPacketRTP(packet *bvrtc.Packet) {
	log.Println(packet.RTP.PayloadType, packet.NTP, packet.PTS, packet.Format.Format().Codec())

	switch packet.Format.Format().(type) {
	case *format.H264, *format.H265, *format.G711, *format.G726:
		if data, err := packet.Format.Decode(packet.RTP); err != nil {
			log.Println(err)
		} else {
			log.Println(len(data))
		}

	case *format.PS:
		err := packet.Format.DecodePS(packet.RTP, func(data []byte, cid mpeg2.PS_STREAM_TYPE, pts time.Duration) {
			log.Println(len(data), cid, pts)
		})
		if err != nil {
			log.Println(err)
		}
	default:
		log.Println("unknown format", packet.Format.Format())
	}

}

func (c *pcHandle) OnPacketRTCP(packet *rtcp.Header, raw []byte) {
	log.Println(packet)
}

func (c *pcHandle) OnPacketLost(err error) {
	log.Println(err)
}

func (c *pcHandle) OnDecodeError(err error) {
	log.Println(err)
}

func (c *pcHandle) OnSessionError(err error) {
	log.Println(err)
}

func main() {
	api := api.NewAPI(api.ClientConfig{
		Scheme:   "http",
		Host:     "192.168.88.11",
		Port:     9780,
		Username: "admin",
		Password: "123456",
	})
	if err := api.Login(); err != nil {
		log.Println(err)
		return
	}

	peerConnection := bvrtc.NewPeerConnection(&pcHandle{})

	// 创建 Offer
	offer, err := peerConnection.CreateOffer(&description.Session{
		Medias: []*description.Media{
			{
				Type:        description.MediaTypeVideo,
				ID:          "0",
				Direction:   sdp.DirectionRecvOnly,
				SSRC:        111,
				CName:       "uct",
				StreamLabel: "40615a81a567c722",
				Label:       "video0",
				Formats: []format.Format{
					&format.H264{
						PayloadTyp:        96,
						SPS:               nil,
						PPS:               nil,
						PacketizationMode: 1,
					},
				},
			},
			{
				Type:        description.MediaTypeAudio,
				ID:          "1",
				Direction:   sdp.DirectionRecvOnly,
				SSRC:        222,
				CName:       "uct",
				StreamLabel: "40615a81a567c722",
				Label:       "audio0",
				Formats: []format.Format{
					&format.G711{
						PayloadTyp:   8,
						MULaw:        false,
						SampleRate:   8000,
						ChannelCount: 1,
					},
					&format.File{
						PayloadTyp: 96,
					},
				},
			},
		},
	})
	if err != nil {
		log.Println(err)
		return
	}

	// 设置本地SDP
	peerConnection.SetLocalDescription(offer)
	bytesOffer, err := offer.MarshalBytes()
	if err != nil {
		log.Println(err)
		return
	}

	// 打开通道
	if dialogId, bytesAnswer, err := api.OpenDialog("PU_34020000001320000001", 320000001, bytesOffer); err != nil {
		log.Println(err)
		return
	} else {
		log.Printf("发送SDP: \n%v", string(bytesOffer))
		log.Printf("接收SDP: \n%v", string(bytesAnswer))
		_ = dialogId

		var answer description.Session
		_ = answer.UnmarshalBytes(bytesAnswer)

		// 设置远程SDP
		peerConnection.SetRemoteDescription(&answer)
	}

	// 创建解码器(不创建解码器, 收到rtp包后无法解码)
	peerConnection.RangeRemoteFormat(func(media *bvrtc.Media, clientFormat *bvrtc.Format) {
		if !media.HaveSender() {
			// 远端没有数据发送者, 即: 这个media接收不到数据, 不需要创建解码器
			return
		}
		_ = clientFormat.CreateDecoder()
	})

	// 创建编码器
	peerConnection.RangeLocalFormat(func(media *bvrtc.Media, clientFormat *bvrtc.Format) {
		if !media.HaveSender() {
			// 没有数据发送者
			return
		}

		_ = clientFormat.CreateEncoder()

		pts := time.Duration(40) * time.Millisecond
		ntp := time.Now()

		if packets, err := clientFormat.Encode([][]byte{[]byte("hello")}, pts); err == nil {
			for _, packet := range packets {
				_ = clientFormat.WritePacketRTP(packet, ntp)
			}
		}
	})

	// 开始传输
	_ = peerConnection.Start()

	defer peerConnection.Close()

	ctx, cancel := signal.NotifyContext(context.TODO(), syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
	defer cancel()

	<-ctx.Done()
}
